home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
os2
/
pmnos11s
/
lpdsubr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-30
|
36KB
|
1,534 lines
/* Internet LPD Server subroutines
* written by David Johnson (dave@cs.olemiss.edu)
*
* This code is in the public domain.
*
* Revision History:
*
* Revision 1.4 91/09/27 dave (from Hans-Juergen)
* Changed definitions of default files to handle changing NOS logical
* root directory
* Actually retrieve the page cost (co) from printcap for pac
*
* Revision 1.3 91/09/19 dave
* Read the ty capability even when interface is not an internal device
*
* Revision 1.2 91/09/17 dave
* Moved output processing flags to device structure so all device types
* can use them
*
* Revision 1.1 91/09/14 dave (from marko winblad)
* Perform an ioctl on DOS device to make sure it is opened in "binary" mode
*
* Revision 1.0 91/09/04 dave
* Initial Release
*
*/
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <time.h>
#include <sys/stat.h>
#ifdef __TURBOC__
#include <io.h>
#include <dir.h>
#endif
#include "global.h"
#include "mbuf.h"
#include "proc.h"
#include "iface.h"
#include "asy.h"
#include "i8250.h"
#include "devparam.h"
#include "socket.h"
#include "dirutil.h"
#include "commands.h"
#include "files.h"
#include "lp.h"
#include "lpd.h"
#include "lpdfilt.h"
/* in files.c */
extern char *roordircat __ARGS((char *directory));
/* in lpd.c */
extern int is_lpd_active __ARGS((void));
/* local functions - public */
int get_acct_info __ARGS((char *queue, char **af, int *pc));
int get_job_list __ARGS((char *directory, struct job_entry **job_list));
char **get_queue_list __ARGS((void));
char *get_spool_dir __ARGS((char *queue));
struct LPDstatus *get_status_entry __ARGS((char *queue));
int is_unspooler_active __ARGS((char *queue, char **job));
int kill_unspooler __ARGS((char *queue));
void lpd_log __ARGS((struct LPDtrans *LPD, char *message, ...));
char *read_printcap __ARGS((struct LPDtrans *LPD, char *queue));
int read_status __ARGS((char *queue, unsigned int *flags, unsigned int *next_seq, char **message));
void set_status_message __ARGS((char **dest, char *message, ...));
char *time_string __ARGS((void));
/* local functions - exported to lpd.c */
void free_queue_status __ARGS((void));
int get_new_sequence_no __ARGS((struct LPDtrans *LPD));
int init_queue_status __ARGS((void));
/* local functions - exported to lpdunsp.c */
int cf_parse __ARGS((struct LPDtrans *LPD, FILE *cfp));
int close_device __ARGS((struct LPDtrans *LPD));
void free_job __ARGS((struct LPDjob *job));
struct LPDdevice *get_device_entry __ARGS((char *device_name));
int open_device __ARGS((struct LPDtrans *LPD));
int save_status __ARGS((char *queue, unsigned int flags, unsigned int next_seq));
/* local functions - exported to lpc.c */
int clear_status_flag __ARGS((char *queue, int flag));
int get_job_count __ARGS((char *queue));
int set_status_flag __ARGS((char *queue, int flag));
int signal_queue __ARGS((char *queue));
/* local functions - private */
static int job_compare __ARGS((char *entry1, char *entry2));
static char *pc_get_entry __ARGS((char *bp, char *name));
static int pc_get_number __ARGS((char *bp, char *id));
static int pc_get_flag __ARGS((char *bp, char *id));
static char *pc_get_string __ARGS((char *bp, char *id, char **area));
static unsigned int get_queue_count __ARGS((void));
static char *get_primary_queue_name __ARGS((char *queue));
static void read_lock_file __ARGS((char *directory, unsigned int *flags, unsigned int *next_seq));
static void set_device_params __ARGS((struct LPDtrans *LPD, char *params));
static void write_lock_file __ARGS((char *directory, unsigned int flags, unsigned int next_seq));
static int load_status __ARGS((char *queue, unsigned int *flags, unsigned int *next_seq));
static void write_lock_file __ARGS((char *directory, unsigned int flags, unsigned int next_seq));
static void read_lock_file __ARGS((char *directory, unsigned int *flags, unsigned int *next_seq));
static void i_lpd_log __ARGS((struct LPDtrans *LPD, char *message, va_list args));
static void i_set_status_message __ARGS((char **dest, char *message, va_list args));
/* Status messages */
static char checking[] = "Checking queue at %s";
static char done[] = "Work done at %s";
static char processing[] = "Processing, active job started %s";
static char busy_device[] = "Waiting for %s to become free since %s";
static char offline_device[] = "Waiting for %s to become ready since %s (offline?)";
static char device_opened[] = "Printer %s output %s opened at %s";
static struct LPDstatus *queue_list;
/*
* All devices which are supported
*/
static struct LPDdevice device_list[] = {
{"LPT1", 0},
{"LPT2", 0},
{"LPT3", 0},
{"COM1", 0},
{"COM2", 0},
{"COM3", 0},
{"COM4", 0},
{"sl1" , 0}, /* internal NOS serial interfaces */
{"sl2" , 0},
{"sl3" , 0},
{"sl4" , 0},
{ NULL , 0}};
/*
* Scan spool directory and return the list of jobs found in job order
*/
int
get_job_list( directory, job_list )
char *directory;
struct job_entry **job_list;
{
char *strdup(), *path, *cf_path;
struct ffblk file_info;
struct stat statbuf;
struct job_entry *tmp_job_list;
unsigned int job_count, job_list_size;
path = pathname( directory, "cf*.*" );
job_count = 0;
tmp_job_list = callocw( 20, sizeof( struct job_entry ) );
job_list_size = 20;
if( findfirst( path, &file_info, 0 ) == 0 ) {
tmp_job_list[job_count].j_name = strdup( file_info.ff_name );
tmp_job_list[job_count].j_priority = file_info.ff_name[2];
cf_path = pathname( directory, file_info.ff_name );
stat( cf_path, &statbuf );
free( cf_path );
tmp_job_list[job_count].j_time = statbuf.st_mtime;
job_count++;
YIELD;
while( findnext( &file_info ) == 0 ) {
tmp_job_list[job_count].j_name = strdup( file_info.ff_name );
tmp_job_list[job_count].j_priority = file_info.ff_name[2];
cf_path = pathname( directory, file_info.ff_name );
stat( cf_path, &statbuf );
free( cf_path );
tmp_job_list[job_count].j_time = statbuf.st_mtime;
if( ++job_count > job_list_size ) {
job_list_size += 20;
tmp_job_list = realloc( tmp_job_list,
job_list_size*sizeof(struct job_entry) );
}
YIELD;
}
YIELD;
qsort( (char *)tmp_job_list, job_count, sizeof( struct job_entry ), job_compare );
}
free( path );
if( job_count == 0 ) {
free( tmp_job_list );
*job_list = NULL;
} else {
*job_list = tmp_job_list;
}
YIELD;
return job_count;
}
/*
* Compare two job entries for qsort
*/
static int
job_compare( entry1, entry2 )
char *entry1, *entry2;
{
struct job_entry *p1, *p2;
p1 = (struct job_entry *)entry1;
p2 = (struct job_entry *)entry2;
if( (p1)->j_priority < (p2)->j_priority )
return -1;
if( (p1)->j_priority > (p2)->j_priority )
return 1;
if( (p1)->j_time < (p2)->j_time )
return -1;
if( (p1)->j_time > (p2)->j_time )
return 1;
return 0;
}
/*
* Convert string to upper case
*/
static void
uppercase_string( string )
char *string;
{
char *cp = string;
while( *cp ) {
if( islower( *cp ) )
*cp = toupper( *cp );
cp++;
}
}
/*
* Read the printcap entries use in printing and spooling.
* Return the primary queue name.
*/
char *
read_printcap( LPD, queue )
struct LPDtrans *LPD;
char *queue;
{
struct iface *ifp;
char *bp, *pcptr, *path;
char *primary_name;
FILE *fp;
LPD->pc = (struct LPDpr *)mallocw( sizeof(struct LPDpr) );
bp = LPD->pc->buffer;
if( (primary_name = pc_get_entry( bp, queue )) == NULL ) {
tprintf( "queue %s not found.\n", queue );
return NULL;
}
LPD->name = primary_name;
pcptr = LPD->pc->strings;
if( (LPD->pc->SD = pc_get_string( bp, "sd", &pcptr )) == NULL )
LPD->pc->SD = Lpdsd;
if( *LPD->pc->SD != '/' )
LPD->pc->SD = rootdircat( LPD->pc->SD );
/*
* Check that spool directory exists
*/
path = pathname( LPD->pc->SD, "testfile" );
fp = fopen( path, "w" );
if( fp == NULL ) {
tprintf( "lpd: spool directory (%s) may not exist\n", LPD->pc->SD );
free( path );
return NULL;
}
fclose( fp );
remove( path );
free( path );
YIELD;
if( (LPD->pc->LP = pc_get_string( bp, "lp", &pcptr )) == NULL )
LPD->pc->LP = D_DEVLP;
if( (ifp = if_lookup( LPD->pc->LP )) != NULL ) {
/* INTERNAL DEVICE; MUST BE SERIAL PORT */
if( (LPD->pc->BR = pc_get_number( bp, "br" )) < 0 )
LPD->pc->BR = D_BAUDRATE;
(*ifp->ioctl)( ifp, PARAM_SPEED, TRUE, LPD->pc->BR );
} else {
uppercase_string( LPD->pc->LP );
}
LPD->pc->TY = pc_get_string( bp, "ty", &pcptr );
if( (LPD->pc->LF = pc_get_string( bp, "lf", &pcptr )) == NULL )
LPD->pc->LF = Lpdlogfile;
if( *LPD->pc->LF != '/' )
LPD->pc->LF = rootdircat( LPD->pc->LF );
if( (LPD->pc->FF = pc_get_string( bp, "ff", &pcptr )) == NULL )
LPD->pc->FF = D_FF;
if( (LPD->pc->PW = pc_get_number( bp, "pw" )) < 0 )
LPD->pc->PW = D_WIDTH;
if( (LPD->pc->PL = pc_get_number( bp, "pl" )) < 0 )
LPD->pc->PL = D_LENGTH;
if( (LPD->pc->PX = pc_get_number( bp, "px" )) < 0 )
LPD->pc->PX = D_PWIDTH;
if( (LPD->pc->PY = pc_get_number( bp, "py" )) < 0 )
LPD->pc->PY = D_PLENGTH;
if( (LPD->pc->MC = pc_get_number( bp, "mc" )) < 0 )
LPD->pc->MC = D_MAXCOPIES;
if( (LPD->pc->MX = pc_get_number( bp, "mx" )) < 0 )
LPD->pc->MX = D_MAXJOBSIZE;
if( (LPD->pc->IF = pc_get_string( bp, "if", &pcptr )) == NULL )
LPD->pc->IF = D_IF;
if( (LPD->pc->OF = pc_get_string( bp, "of", &pcptr )) == NULL )
LPD->pc->OF = D_OF;
if( (LPD->pc->FX = pc_get_string( bp, "fx", &pcptr )) == NULL )
LPD->pc->FX = D_FILTERS;
YIELD;
/* Other filter specifications - presently not used */
LPD->pc->CF = pc_get_string( bp, "cf", &pcptr );
LPD->pc->DF = pc_get_string( bp, "df", &pcptr );
LPD->pc->GF = pc_get_string( bp, "gf", &pcptr );
LPD->pc->NF = pc_get_string( bp, "nf", &pcptr );
LPD->pc->TF = pc_get_string( bp, "tf", &pcptr );
LPD->pc->VF = pc_get_string( bp, "vf", &pcptr );
LPD->pc->CM = pc_get_string( bp, "cm", &pcptr );
LPD->pc->AF = pc_get_string( bp, "af", &pcptr );
if( *LPD->pc->AF != '/' )
LPD->pc->AF = rootdircat( LPD->pc->AF );
LPD->pc->LD = pc_get_string( bp, "ld", &pcptr );
LPD->pc->TR = pc_get_string( bp, "tr", &pcptr );
LPD->pc->JL = pc_get_string( bp, "jl", &pcptr );
LPD->pc->JT = pc_get_string( bp, "jt", &pcptr );
LPD->pc->FL = pc_get_string( bp, "fl", &pcptr );
LPD->pc->FT = pc_get_string( bp, "ft", &pcptr );
YIELD;
LPD->pc->AB = pc_get_flag( bp, "ab" );
LPD->pc->FO = pc_get_flag( bp, "fo" );
LPD->pc->FQ = pc_get_flag( bp, "fq" );
LPD->pc->HL = pc_get_flag( bp, "hl" );
LPD->pc->SB = pc_get_flag( bp, "sb" );
LPD->pc->SC = pc_get_flag( bp, "sc" );
LPD->pc->SF = pc_get_flag( bp, "sf" );
LPD->pc->SH = pc_get_flag( bp, "sh" );
LPD->pc->SS = pc_get_flag( bp, "ss" );
/* PostScript capabilities */
LPD->pc->PS = pc_get_string( bp, "ps", &pcptr );
LPD->pc->PE = pc_get_string( bp, "pe", &pcptr );
LPD->pc->DP = pc_get_flag( bp, "dp" );
YIELD;
return( primary_name );
}
/*
* Set the device characteristics of an internal NOS interface
*/
static void
set_device_params( LPD, params)
struct LPDtrans *LPD;
char *params;
{
struct iface *ifp = NULL;
int negate;
char *tempparams, *option;
if( LPD->status->type == INTERNAL )
ifp = LPD->status->device.ifp;
tempparams = strdup( params );
option = strtok( tempparams, " " );
while( option ) {
negate = 0;
if( *option == '-' ) {
negate = 1;
option++;
}
if( strncmp( option, "even", 4 ) == 0 && ifp ) {
if( negate ) /* not even */
(*ifp->ioctl)( ifp, PARAM_PARITY, TRUE, 0 );
else /* even */
(*ifp->ioctl)( ifp, PARAM_PARITY, TRUE, 1 );
} else if( strncmp( option, "odd", 3 ) == 0 && ifp ) {
if( negate ) /* not odd */
(*ifp->ioctl)( ifp, PARAM_PARITY, TRUE, 0 );
else /* odd */
(*ifp->ioctl)( ifp, PARAM_PARITY, TRUE, 2 );
} else if( strncmp( option, "rts", 3 ) == 0 && ifp ) {
(*ifp->ioctl)( ifp, PARAM_RTS, TRUE, !negate );
} else if( strncmp( option, "dtr", 3 ) == 0 && ifp ) {
(*ifp->ioctl)( ifp, PARAM_DTR, TRUE, !negate );
} else if( strncmp( option, "nl", 2 ) == 0 ) {
if( negate )
LPD->device->flags &= ~CRMOD;
else
LPD->device->flags |= CRMOD;
} else if( strncmp( option, "tabs", 4 ) == 0 ) {
if( negate )
LPD->device->flags |= XTABS;
else
LPD->device->flags &= ~XTABS;
}
option = strtok( NULL, " " );
}
free( tempparams );
}
/*
* Open the specified device if it is not busy, else wait for it to free.
*/
int
open_device( LPD )
struct LPDtrans *LPD;
{
struct LPDstatus *status = LPD->status;
if( status->device_open == 0 ) {
set_status_message( &LPD->status->message, busy_device, LPD->pc->LP, time_string() );
while( LPD->device->busy ) /* another unspooler is using */
YIELD;
if( (status->device.ifp = if_lookup( LPD->pc->LP )) == NULLIF ) {
/* MUST BE A DOS FILE DEVICE */
status->type = EXTERNAL;
if( (status->device.fp = fopen( LPD->pc->LP, "ab" )) == NULL ) {
tprintf( "device could not be opened\n" );
return -1;
}
/*
* Make sure device is opened in "binary" mode
*/
#ifdef LPD_DEBUG
tprintf( "isatty(%d) returns %d\n",
fileno( status->device.fp ),
isatty( fileno( status->device.fp ) ));
tflush();
#endif
if( isatty( status->device.fp->fd ) ) {
#ifdef LPD_DEBUG tprintf( "ioctl(%d,0) returns %04x\n",
fileno( status->device.fp ),
ioctl( fileno( status->device.fp ), 0);
tflush();
#endif
ioctl( fileno( status->device.fp ), 1,
0xff &
(ioctl( fileno( status->device.fp ),0)
| 0x20 ) );
}
#ifdef LPD_DEBUG
tprintf( "ioctl(%d,0) returns %04x\n",
fileno( status->device.fp ),
ioctl( fileno( status->device.fp ), 0 ) );
tflush();
#endif
} else {
if( (status->device.ifp)->dev >= ASY_MAX
|| Asy[(status->device.ifp)->dev].iface != status->device.ifp ){
/* INVALID INTERNAL INTERFACE; MAKE EXTERNAL */
status->type = EXTERNAL;
if( (status->device.fp = fopen( LPD->pc->LP, "ab" )) == NULL ) {
tprintf( "device could not be opened\n" );
return -1;
}
} else {
status->type = INTERNAL;
}
}
if( LPD->pc->TY )
set_device_params( LPD, LPD->pc->TY );
LPD->device->busy = 1; /* mark device as busy */
LPD->status->device_open = 1;
LPD->status->jobno = 0;
set_status_message( &LPD->status->message, device_opened, LPD->name, LPD->pc->LP, time_string() );
}
return 0;
}
/*
* Close the device file handle and free device
*/
int
close_device( LPD )
struct LPDtrans *LPD;
{
if( LPD->status->device_open ) {
if( LPD->status->type == EXTERNAL ) {
fclose( LPD->status->device.fp );
LPD->status->device.fp = (FILE *)0;
}
LPD->status->device_open = 0;
LPD->device->busy = 0;
}
}
/*
* Read the control file and extract necessary entries.
* Returns -1 if data file(s) is not found or size exceeds MX.
*/
int
cf_parse( LPD, cfp )
struct LPDtrans *LPD;
FILE *cfp;
{
char line[81], *ptr, *strdup();
char *path;
struct LPDjob *job;
job = LPD->job;
while( fgets( line, 80, cfp ) != NULL ) {
rip( line );
switch( *line ) {
case 'N':
case 'U':
/* ignore */
break;
case 'C':
job->class = strdup( line+1 );
break;
case 'D':
job->date = strdup( line+1 );
break;
case 'H':
job->hostname = strdup( line+1 );
break;
case 'I':
job->indent = atoi( line+1 );
break;
case 'J':
job->jobname = strdup( line+1 );
break;
case 'L':
job->username = strdup( line+1 );
break;
case 'M':
job->mail = strdup( line+1 );
break;
case 'P':
job->person = strdup( line+1 );
break;
case 'S':
job->noheader = strdup( line+1 );
break;
case 'R':
job->account = strdup( line+1 );
break;
case 'W':
job->width = atoi( line+1 );
break;
case 'T':
job->title = strdup( line+1 );
break;
default:
if( islower( *line ) ) {
struct stat fstatus;
if( strchr( LPD->pc->FX, *line ) == NULL )
return -1;
path = pathname( LPD->pc->SD, line+1 );
if( stat( path, &fstatus ) != 0 ) {
free( path );
lpd_log( LPD, "cf_parse: %s not found", line+1 );
return -1;
}
free( path );
job->size += (fstatus.st_size + 1023)/1024;
if( LPD->pc->MX && job->size > LPD->pc->MX ) {
lpd_log( LPD, "cf_parse: job %s exceeds max. job size", job->jobname );
return -1;
}
}
}
YIELD;
}
/*
* Handle missing items
*/
if( LPD->job->width == 0 )
LPD->job->width = LPD->pc->PW;
if( LPD->job->class == NULL && LPD->job->hostname )
LPD->job->class = strdup( LPD->job->hostname );
return 0;
}
/*
* free the job fields allocated in cf_parse
*/
void
free_job( job )
struct LPDjob *job;
{
if( job == NULL )
return;
if( job->class )
free( job->class );
if( job->date )
free( job->date );
if( job->hostname )
free( job->hostname );
if( job->jobname )
free( job->jobname );
if( job->username )
free( job->username );
if( job->mail )
free( job->mail );
if( job->person )
free( job->person );
if( job->noheader )
free( job->noheader );
if( job->account )
free( job->account );
if( job->title )
free( job->title );
free( job );
job = NULL;
}
/******************************************************************************
** **
** Printcap file handling routines **
** **
******************************************************************************/
/*
** pc_get_entry - get the printcap entry for printer name, and put it
** in bp (which must be an array of 1024 chars). Returns
** PRIMARY_NAME if printcap entry found, NULL if not found or
** printcap file not found.
*/
static char *
pc_get_entry( bp, name )
char *bp, *name;
{
FILE *fp;
char *cp, *pn, *primary_name;
short len = strlen( name );
#ifdef LPD_DEBUG
tprintf( "pc_get_entry( %s )\n", name );
tflush();
#endif
if( (fp = fopen( Lpdprintcap, "r" )) == (FILE *) NULL )
return( NULL );
while( fgets( bp, 1024, fp ) != NULL ) {
/* skip comments */
if( *bp == '#' )
continue;
for( cp = bp; isspace( *cp ); cp++ )
;
do {
if( strncmp( name, cp, len ) == 0 ) {
while( *(cp = &bp[strlen(bp) - 2]) == '\\' )
fgets( cp, 1024, fp );
fclose( fp );
len = 0;
cp = bp;
while( *cp && *cp != ':' && *cp != '|' ) {
++len;
++cp;
}
primary_name = (char *)mallocw(len+1);
cp = bp;
pn = primary_name;
while( *cp && *cp != ':' && *cp != '|' )
*pn++ = *cp++;
*pn = NULL;
return( primary_name );
}
while( *cp && *cp != '|' )
cp++;
if( *cp ) /* skip | */
cp++;
} while( *cp && *cp != '\\' );
}
fclose( fp );
return( NULL );
}
/*
** pc_get_number - get the numeric printer capability corresponding
** to id. Returns the value, -1 if invalid.
*/
static int
pc_get_number( bp, id )
char *bp, *id;
{
char *cp;
int ret;
if( (cp = bp) == NULL || id == NULL )
return( -1 );
while( *++cp != ':' )
;
for( ++cp; *cp; ) {
while( isspace( *cp ) )
cp++;
if( strncmp( cp, id, 2) == 0 ) {
while( *cp && *cp != ':' && *cp != '#' )
cp++;
if( *cp != '#' )
return( -1 );
for( ret = 0, cp++; *cp && isdigit( *cp ); cp++ )
ret = ret * 10 + *cp - '0';
return( ret );
}
while( *cp && *cp != ':' )
cp++;
if( *cp )
cp++;
}
return( -1 );
}
/*
** pc_get_flag - get the boolean flag corresponding to id. Returns
** -1 if invalid, FALSE if the flag is not in the printcap
** entry, or TRUE if it is present.
*/
static int
pc_get_flag( bp, id )
char *bp, *id;
{
char *cp;
if( (cp = bp) == NULL || id == NULL )
return( -1 );
while( *++cp != ':' )
;
for( ++cp; *cp; ) {
while( isspace( *cp ) )
cp++;
if( strncmp( cp, id, 2) == 0 )
return( TRUE );
while( *cp && *cp != ':' )
cp++;
if( *cp )
cp++;
}
return( FALSE );
}
/*
** pc_get_string - get the string capability corresponding to id and place
** it in area (advancing area to same time). Expand escape
** sequences etc. Returns the string, of NULL if it can't
** do it.
*/
static char *
pc_get_string( bp, id, area )
char *bp, *id, **area;
{
char *cp, *ret;
int i;
if( (cp = bp) == NULL || id == NULL )
return( NULL );
while( *++cp != ':' )
;
for( ++cp; *cp; ) {
while( isspace( *cp ) )
cp++;
if( strncmp( cp, id, 2) == 0 ) {
while( *cp && *cp != ':' && *cp != '=' )
cp++;
if( *cp != '=' )
return( NULL );
for( ret = *area, cp++; *cp && *cp != ':'; (*area)++, cp++ )
switch( *cp ) {
case '^':
**area = *++cp - 'A';
break;
case '\\':
switch( *++cp ) {
case 'E':
**area = '\033';
break;
case 'n':
**area = '\n';
break;
case 'r':
**area = '\r';
break;
case 't':
**area = '\t';
break;
case 'b':
**area = '\b';
break;
case 'f':
**area = '\f';
break;
case '0':
case '1':
case '2':
case '3':
for( i = 0; *cp && isdigit( *cp ); cp++ )
i = i * 8 + *cp - '0';
**area = i & 0x7f; /* strip high bit */
cp--;
break;
case '^':
case '\\':
**area = *cp;
break;
}
break;
default:
**area = *cp;
}
*(*area)++ = '\0';
return( ret );
}
while( *cp && *cp != ':' )
cp++;
if( *cp )
cp++;
}
return( NULL );
}
/*
* Get a count of the number of queues specified in the printcap
*/
static unsigned int
get_queue_count()
{
FILE *fp;
unsigned int queue_count = 0;
char *buffer;
#ifdef LPD_DEBUG
tprintf( "get_queue_count()\n" );
tflush();
#endif
if( (fp = fopen( Lpdprintcap, "r" )) == (FILE *) NULL )
return NULL;
buffer = (char *)mallocw( 1024 );
while( fgets( buffer, 1024, fp ) != NULL ) {
/* skip comments */
if( *buffer == '#' )
continue;
if( *buffer != '\n' ) {
queue_count++;
while( *(buffer + strlen( buffer ) - 2) == '\\' )
fgets( buffer, 1024, fp );
}
YIELD;
}
fclose( fp );
free( buffer );
return( queue_count );
}
/*
* Scans the printcap file and extracts the names of all queues.
*/
char **
get_queue_list(void)
{
FILE *fp;
char *cp, *strdup(), save;
char *buffer;
char **queue_list;
unsigned int queue_count = 0, queue_entry = 0;
#ifdef LPD_DEBUG
tprintf( "get_queue_list()\n" );
tflush();
#endif
queue_count = get_queue_count();
if( queue_count == 0 ) {
tprintf( "no queues defined in printcap file\n" );
return NULL;
}
queue_list = callocw( queue_count+1, sizeof( char * ) );
buffer = mallocw( 1024 );
fp = fopen( Lpdprintcap, "r" );
while( fgets( buffer, 1024, fp ) != NULL ) {
/* skip comments */
if( *buffer == '#' )
continue;
for( cp = buffer; isspace( *cp ) && *cp != '\n'; cp++ )
;
while( *cp && *cp != '|' && *cp != ':'
&& *cp != '\\' && *cp != '\n' )
cp++;
save = *cp;
*cp = NULL;
if( *buffer )
queue_list[ queue_entry++ ] = strdup( buffer );
*cp = save;
while( *(buffer + strlen( buffer ) - 2) == '\\' )
fgets( buffer, 1024, fp );
YIELD;
}
queue_list[ queue_entry ] = NULL;
fclose( fp );
free( buffer );
return( queue_list );
}
/*
* Get the SD (spool directory) associated with the specified queue
* from the printcap
*/
char *
get_spool_dir( queue )
char *queue;
{
char *cp, *strdup();
char *bp, *sp, *osp; /* buffer and string pointers */
char *primary_name;
char *sd;
bp = (char *)mallocw( 1024 );
/* look up corresponding printcap entry */
if( (primary_name = pc_get_entry( bp, queue )) == NULL ) {
free( bp );
return NULL;
}
free( primary_name );
osp = sp = (char *)mallocw( 128 );
if( (cp = pc_get_string( bp, "sd", &sp )) == NULL )
cp = Lpdsd;
if( *cp != '/' )
cp = rootdircat( cp );
sd = strdup( cp );
free( osp );
free( bp );
return sd;
}
/*
* Get the AF (accounting file) and CO (page cost) associated
* with the specified queue from the printcap
*/
int
get_acct_info( queue, af, pc )
char *queue, **af;
int *pc;
{
char *cp, *strdup();
char *bp, *sp, *osp; /* buffer and string pointers */
char *primary_name;
bp = (char *)mallocw( 1024 );
/* look up corresponding printcap entry */
if( (primary_name = pc_get_entry( bp, queue )) == NULL ) {
free( bp );
return 1;
}
free( primary_name );
osp = sp = (char *)mallocw( 128 );
if( (cp = pc_get_string( bp, "af", &sp )) == NULL ) {
*af = NULL;
} else {
*af = strdup( cp );
}
if( **af != '/' )
*af = rootdircat( *af );
if( (*pc = pc_get_number( bp, "co" )) < 0 )
*pc = 0;
free( osp );
free( bp );
return 0;
}
/*
* Set up internal queue status structures. Read previous status from
* disk or create a new status file.
*/
int
init_queue_status(void)
{
char **pr, **opr, *strdup(); /* list of print queues */
char *sd;
unsigned int count;
struct LPDstatus *ptr;
#ifdef LPD_DEBUG
tprintf( "init_queue_status()\n" );
tflush();
#endif
count = get_queue_count();
if( count == 0 ) {
tprintf( "no queues defined in printcap file\n" );
return -1;
}
queue_list = ptr = calloc( count+1, sizeof( struct LPDstatus ) );
for( opr = pr = get_queue_list(); *pr; ++pr, ++ptr ){
/* look up corresponding printcap entry */
sd = get_spool_dir( *pr );
read_lock_file( sd, &ptr->flags, &ptr->next_seq );
free( sd );
ptr->name = strdup( *pr );
ptr->device_open = 0;
ptr->type = EXTERNAL; /* These will be set on the */
ptr->device.fp = (FILE *)0; /* call to open_device() */
ptr->jobno = 0;
ptr->busy = 0;
ptr->message = NULL;
free( *pr );
}
free( *pr ); /* null entry */
free( opr );
/* last one is NULL */
ptr->name = NULL;
return 0;
}
/*
* Free internal queue status structures.
*/
void
free_queue_status(void)
{
struct LPDstatus *ptr;
#ifdef LPD_DEBUG
tprintf( "free_queue_status()\n" );
tflush();
#endif
for( ptr = queue_list; ptr->name; ptr++ ) {
free( ptr->name );
if( ptr->message != NULL )
free( ptr->message );
}
free( queue_list );
}
/*
* Obtain new sequence number for a new job
*/
int
get_new_sequence_no( LPD )
struct LPDtrans *LPD;
{
if( LPD->status == NULL ) {
if( (LPD->status = get_status_entry( LPD->name )) == NULL )
return -1;
}
LPD->status->next_seq++;
write_lock_file( LPD->pc->SD, LPD->status->flags, LPD->status->next_seq );
return( LPD->status->next_seq-1 );
}
/*
* Read physical queue lock file contents. If given file does not exist,
* one is created with the default values.
*/
static void
read_lock_file( directory, flags, next_seq )
char *directory;
unsigned int *flags;
unsigned int *next_seq;
{
char *path;
int fd;
path = pathname( directory, D_LOCK );
if( (fd = open( path, O_RDONLY )) < 0 ) {
fd = creat( path, 0644 );
*flags = QUEUE_ENABLED | PRINT_ENABLED;
*next_seq = 1;
write( fd, flags, sizeof( *flags ) );
write( fd, next_seq, sizeof( *next_seq ) );
lseek( fd, 0L, 0 );
}
read( fd, flags, sizeof( *flags ) );
read( fd, next_seq, sizeof( *next_seq ) );
close( fd );
free( path );
YIELD;
}
/*
* Write values to physical queue lock file.
*/
static void
write_lock_file( directory, flags, next_seq )
char *directory;
unsigned int flags;
unsigned int next_seq;
{
char *path;
int fd;
path = pathname( directory, D_LOCK );
fd = open( path, O_WRONLY|O_TRUNC|O_CREAT, 0644 );
write( fd, &flags, sizeof( flags ) );
write( fd, &next_seq, sizeof( next_seq ) );
close( fd );
free( path );
YIELD;
}
/*
* Load the status file for the given queue and extract its contents
*/
static int
load_status( queue, flags, next_seq )
char *queue;
unsigned int *flags;
unsigned int *next_seq;
{
char *sd;
if( (sd = get_spool_dir( queue )) == NULL )
return -1;
read_lock_file( sd, flags, next_seq );
free( sd );
return 0;
}
/*
* Read the status of the specified queue from memory or disk as necessary
*/
int
read_status( queue, flags, next_seq, message )
char *queue;
unsigned int *flags;
unsigned int *next_seq;
char **message;
{
char *primary_name;
struct LPDstatus *status;
#ifdef LPD_DEBUG
tprintf( "read_status( %s )\n", queue );
tflush();
#endif
if( is_lpd_active() ) { /* Server is active */
primary_name = get_primary_queue_name( queue );
if( (status = get_status_entry( primary_name )) == NULL ) {
free( primary_name );
return -1;
}
free( primary_name );
*flags = status->flags;
*next_seq = status->next_seq;
*message = status->message;
} else {
*message = "LPD server is not active";
return( load_status( queue, flags, next_seq ) );
}
return 0;
}
/*
* Set the flag bits specified in the queue status entry
*/
int
set_status_flag( queue, flag )
char *queue;
int flag;
{
unsigned int flags, next_seq;
char *message;
if( read_status( queue, &flags, &next_seq, &message ) < 0 )
return -1;
flags |= flag;
if( save_status( queue, flags, next_seq ) < 0 )
return -1;
return 0;
}
/*
* Clear the flag bits specified in the queue status entry
*/
int
clear_status_flag( queue, flag )
char *queue;
int flag;
{
unsigned int flags, next_seq;
char *message;
if( read_status( queue, &flags, &next_seq, &message ) < 0 )
return -1;
flags &= ~flag;
if( save_status( queue, flags, next_seq ) < 0 )
return -1;
return 0;
}
int
save_status( queue, flags, next_seq )
char *queue;
unsigned int flags;
unsigned int next_seq;
{
char *sd, *primary_name;
struct LPDstatus *status;
#ifdef LPD_DEBUG
tprintf( "save_status( %s )\n", queue );
tflush();
#endif
if( is_lpd_active() ) { /* Server is active */
primary_name = get_primary_queue_name( queue );
if( (status = get_status_entry( primary_name )) == NULL ) {
free( primary_name );
return -1;
}
free( primary_name );
status->flags = flags;
status->next_seq = next_seq;
}
if( (sd = get_spool_dir( queue )) == NULL )
return -1;
write_lock_file( sd, flags, next_seq );
free( sd );
return 0;
}
/*
* Signal a paused printer
*/
int
signal_queue( queue )
char *queue;
{
unsigned int flags, next_seq;
char *message, *primary_name;
struct LPDstatus *status;
if( read_status( queue, &flags, &next_seq, &message ) < 0 )
return -1;
flags &= ~PAUSED;
if( save_status( queue, flags, next_seq ) < 0 )
return -1;
primary_name = get_primary_queue_name( queue );
if( (status = get_status_entry( primary_name )) == NULL ) {
free( primary_name );
return -1;
}
free( primary_name );
psignal( &status->flags, 1 );
return 0;
}
/*
* Kill the unspooler currently handling the given queue
*/
int
kill_unspooler( queue )
char *queue;
{
char *primary_name;
struct LPDstatus *status;
primary_name = get_primary_queue_name( queue );
if( (status = get_status_entry( primary_name )) == NULL ) {
free( primary_name );
return -1;
}
free( primary_name );
if( status->unspooler_proc != NULLPROC ) {
killproc( status->unspooler_proc );
status->unspooler_proc = NULLPROC;
return 1;
}
return 0;
}
/*
* Return the status of an unspooler for the specified queue.
* Also return the cf_name of the currently active job.
*/
int
is_unspooler_active( queue, job )
char *queue, **job;
{
char *primary_name;
struct LPDstatus *status;
*job = NULL;
if( is_lpd_active() ) {
primary_name = get_primary_queue_name( queue );
if( (status = get_status_entry( primary_name )) == NULL ) {
free( primary_name );
return 0; /* nope */
}
free( primary_name );
if( status->unspooler_proc == NULLPROC )
return 0; /* also not */
*job = status->current_job;
return 1; /* otherwise, must be active */
}
return 0; /* server cannot be active */
}
/*
* Get the job count for the given queue
*/
int
get_job_count( queue )
char *queue;
{
char *path, *sd;
unsigned int job_count = 0;
struct ffblk file_info;
if( (sd = get_spool_dir( queue )) == NULL )
return -1;
path = pathname( sd, "cf*.*" );
free( sd );
if( findfirst( path, &file_info, 0 ) == 0 ) {
job_count++;
while( findnext( &file_info ) == 0 )
job_count++;
}
free( path );
YIELD;
return( job_count );
}
/*
* Return the primary queue name of the (possibly) given queue alias
*/
static char *
get_primary_queue_name( queue )
char *queue;
{
char *bp, *primary_name;
bp = (char *)mallocw( 1024 );
/* look up corresponding printcap entry */
if( (primary_name = pc_get_entry( bp, queue )) == NULL ) {
free( bp );
return NULL;
}
free( bp );
return( primary_name );
}
/*
* locate device entry for the specified printer device
*/
struct LPDdevice *
get_device_entry( device_name )
char *device_name;
{
struct LPDdevice *dptr;
dptr = device_list;
while( dptr->name != NULL ) {
if( strcmp( dptr->name, device_name ) == 0 )
return( dptr );
dptr++;
}
return( NULL ); /* not found */
}
/*
* locate status entry for the specified queue
*/
struct LPDstatus *
get_status_entry( queue )
char *queue;
{
struct LPDstatus *sptr;
sptr = queue_list;
while( sptr->name != NULL ) {
if( strcmp( sptr->name, queue ) == 0 )
return( sptr );
sptr++;
}
return( NULL ); /* not found */
}
/*
* Internal status message routine
*/
static void
i_set_status_message( char **dest, char *message, va_list args )
{
char buffer[128];
vsprintf( buffer, message, args );
rip( buffer );
if( *dest != NULL )
free( *dest );
*dest = strdup( buffer );
}
/*
* Set the status message as specified
*/
void
set_status_message( char **dest, char *message, ... )
{
va_list args;
va_start( args, message );
i_set_status_message( dest, message, args );
va_end( args );
}
/*
* Return a pointer to a static data area containing the formatted date
* and time.
*/
char *
time_string(void)
{
time_t current_time;
time( ¤t_time );
return( ctime( ¤t_time ) );
}
/*
* Internal log routine
*/
static void
i_lpd_log( struct LPDtrans *LPD, char *message, va_list args )
{
char buffer[128], timeb[30];
vsprintf( buffer, message, args );
strcpy( timeb, time_string() );
rip( timeb );
fputs( timeb, LPD->logfp );
fputs( " - ", LPD->logfp );
fputs( buffer, LPD->logfp );
putc( '\n', LPD->logfp );
}
/*
* Log a message to the logfile
*/
void
lpd_log( struct LPDtrans *LPD, char *message, ... )
{
va_list args;
if( LPD->logfp == NULL ) /* no logging */
return;
va_start( args, message );
i_lpd_log( LPD, message, args );
va_end( args );
}